﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Seek -- by Phi</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="alternate" type="application/rss+xml" title="AutoHotkey Forum RSS" href="/forum/rss.php">
<link href="/docs/css/default.css" rel="stylesheet" type="text/css">
<link href="/docs/css/print.css" rel="stylesheet" type="text/css" media="print">
</head>
<body>

<h6>Seek -- by Phi</h6>

<p> Navigating the Start Menu can be a hassle, especially
 if you have installed many programs over time. 'Seek'
 lets you specify a case-insensitive key word/phrase
 that it will use to filter only the matching programs
 and directories from the Start Menu, so that you can
 easily open your target program from a handful of
 matched entries. This eliminates the drudgery of
 searching and traversing the Start Menu.
</p>
<p><a href="Seek_(SearchTheStartMenu).ahk">Download This Script</a> &nbsp;| &nbsp;<a href="index.htm">Other Sample Scripts</a> &nbsp;| &nbsp;<a href="http://www.autohotkey.com">Home</a></p>

<pre class="NoIndent"><em>;*****************************************************************</em>
<em>;</em>
<em>;  Program : Seek</em>
<em>;  Coder   : Phi</em>
<em>;  Updated : Mon Jan 31 10:08:37 2005</em>
<em>;</em>
<em>;  What do you seek, my friend?</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>;  I have a lot of fun coding this, and hope you will</em>
<em>;  enjoy using it too. Feel free to drop me an email with</em>
<em>;  your comments and feedback at: phi1618 (*a.t*) gmail</em>
<em>;  :D0T: com.</em>
<em>;</em>
<em>;  Options:</em>
<em>;    -cache Use the cached directory-listing if available</em>
<em>;           (this is the default mode when no option is specified)</em>
<em>;    -scan  Force a directory scan to retrieve the latest</em>
<em>;           directory listing</em>
<em>;    -scex  Scan &amp; exit (this is useful for scheduling the</em>
<em>;           potentially time-consuming directory-scanning as</em>
<em>;           a background job)</em>
<em>;    -help  Show this help</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>; HOW TO 'SEEK':</em>
<em>;</em>
<em>; 1. 'Seek' is an AutoHotkey script. You can either run it</em>
<em>;    as Seek.ahk (original script) or Seek.exe (compiled</em>
<em>;    executable).</em>
<em>;</em>
<em>;    To obtain Seek.exe, you can download Seek.zip (includes</em>
<em>;    both the source code and the compiled binary) from</em>
<em>;    http://home.ripway.com/2004-10/188589/</em>
<em>;    Otherwise, you can compile Seek.ahk on your own by</em>
<em>;    using AutoHotkey's Ahk2Exe.exe compiler, or you can</em>
<em>;    ask me for a copy via email. The filesize is small at</em>
<em>;    about 200 kbytes. I can be reached at: phi1618 (*a.t*)</em>
<em>;    gmail :D0T: com.</em>
<em>;</em>
<em>;    To use Seek.ahk, first, you'll need to install</em>
<em>;    AutoHotkey v1.0.25 or higher on your PC (download from</em>
<em>;    http://www.autohotkey.com). Next, run the command:</em>
<em>;</em>
<em>;    X:\myTools\AutoHotkey\AutoHotkey.exe Y:\myAHK\Seek.ahk</em>
<em>;</em>
<em>;    Remember to replace X:\myTools and Y:\myAHK with</em>
<em>;    the proper directory names on your PC.</em>
<em>;</em>
<em>; 2. You can place the executable Seek.exe anywhere you</em>
<em>;    want. There is no installation required, it doesn't</em>
<em>;    write anything to your registry, and it doesn't</em>
<em>;    access the Internet at all (no phoning home). To</em>
<em>;    uninstall, simply delete Seek.exe.</em>
<em>;</em>
<em>;    The only 2 files 'Seek' creates are placed in your</em>
<em>;    TMP directory:</em>
<em>;</em>
<em>;      a. _Seek.key  (cache file for last query string)</em>
<em>;      b. _Seek.list (cache file for directory listing)</em>
<em>;</em>
<em>;    If you're a purist, you can delete them manually</em>
<em>;    when you decide to remove 'Seek' from your system.</em>
<em>;</em>
<em>; 3. The most convenient way to run 'Seek' is via a</em>
<em>;    shortcut/hotkey. If you are not already using any</em>
<em>;    hotkey management program on your PC, I highly</em>
<em>;    recommend AutoHotkey. If you don't intend to install</em>
<em>;    any hotkey management program at the moment, you can</em>
<em>;    make use of Windows shortcut feature and bind a</em>
<em>;    shortcut key (e.g. ALT-F1) to launch 'Seek'. This is</em>
<em>;    important so that you can run 'Seek' at anytime and</em>
<em>;    anywhere.</em>
<em>;</em>
<em>; 4. When you run 'Seek' for the first time, it'll scan</em>
<em>;    your Start Menu, and save the directory listing into</em>
<em>;    a cache file.</em>
<em>;</em>
<em>;    The following directories are included in the scanning:</em>
<em>;    - %A_StartMenu%</em>
<em>;    - %A_StartMenuCommon%</em>
<em>;</em>
<em>;    By default, subsequent runs will read from the</em>
<em>;    cache file so as to reduce the loading time. For</em>
<em>;    more info on options, run 'Seek.exe -help'. If you</em>
<em>;    think your Start Menu doesn't contain too many</em>
<em>;    programs, you can choose not to use the cache and</em>
<em>;    instruct 'Seek' to always do a directory scan (via</em>
<em>;    option -scan).  That way, you will always get the</em>
<em>;    latest listing.</em>
<em>;</em>
<em>; 5. When you run 'Seek', a window will appear, waiting</em>
<em>;    for you to enter a key word/phrase. After you have</em>
<em>;    entered a query string, a list of matching records</em>
<em>;    will be displayed. Next, you need to highlight an</em>
<em>;    entry and press &lt;Enter&gt; or click on the 'Open'</em>
<em>;    button to run the selected program or open the</em>
<em>;    selected directory.</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>; TECHNICAL NOTES:</em>
<em>;</em>
<em>; - 'Seek' requires Chris Mallett's AutoHotkey v1.0.25</em>
<em>;   or higher version (http://www.autohotkey.com).</em>
<em>;   Thanks to Chris for his great work on AutoHotkey. :)</em>
<em>;</em>
<em>; - The following environment variables must be valid:</em>
<em>;   a. TMP</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>; KNOWN PROBLEMS:</em>
<em>;</em>
<em>; - Nil</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>; IMPLEMENTED SUGGESTIONS:</em>
<em>;</em>
<em>; - Highlight 1st matching record by default so that</em>
<em>;   user can just hit &lt;Enter&gt; to run it.</em>
<em>;   (Suggested by Yih Yeong)</em>
<em>;</em>
<em>; - Enable double-click on the listing of the search</em>
<em>;   results to launch the program.</em>
<em>;   (Suggested by Yih Yeong &amp; Jack)</em>
<em>;</em>
<em>; - Auto real-time incremental search.</em>
<em>;   (Suggested by Rajat)</em>
<em>;</em>
<em>; - Fuzzy search when user enters multiple query strings,</em>
<em>;   separated by space.</em>
<em>;   (Suggested by Rajat)</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>; SUGGESTED FEATURES (MAY OR MAY NOT BE IMPLEMENTED):</em>
<em>;</em>
<em>; - Log the launch history. List the most frequently</em>
<em>;   used programs at the top of the search results.</em>
<em>;   (Suggested by Yih Yeong)</em>
<em>;</em>
<em>; - Instead of using list box, can it display a series</em>
<em>;   of application icons so that hovering the cursor</em>
<em>;   over the icon will display a tooltip containing the</em>
<em>;   program information (path, etc).</em>
<em>;   (Suggested by Yih Yeong)</em>
<em>;</em>
<em>; - Instead of matching text in the middle, match only</em>
<em>;   those program/directory names that begin with the</em>
<em>;   query string.</em>
<em>;   (Suggested by Stefan)</em>
<em>;</em>
<em>; - Add favorites management. Launch group of programs</em>
<em>;   in a single run.</em>
<em>;   (Suggested by Atomhrt)</em>
<em>;</em>
<em>; - Integrate Seek into the Windows taskbar/toolbar so that</em>
<em>;   it is always available and there is no need to bind a</em>
<em>;   hotkey to launch Seek.</em>
<em>;   (Suggested by Deniz Akay)</em>
<em>;</em>
<em>; - Search by wildcards/regex.</em>
<em>;   (Suggested by Steve)</em>
<em>;</em>
<em>;*****************************************************************</em>
<em>;</em>
<em>; CHANGE HISTORY:</em>
<em>;</em>
<em>; * v1.1.0</em>
<em>; - Initial release.</em>
<em>;</em>
<em>; * v1.1.1</em>
<em>; - Removed maximise-window option since some programs don't</em>
<em>;   function well with it.</em>
<em>; - Added double-click detection to trigger 'Open' function.</em>
<em>;</em>
<em>; * v2.0.0</em>
<em>; - Integrated the 'Seek' popup window into the output screen</em>
<em>;   so that user can re-enter the query string to search for</em>
<em>;   something else without having to exit and run Seek again.</em>
<em>; - Added 'Scan Start-Menu' button.</em>
<em>; - Added real-time incremental search which will auto</em>
<em>;   filter for matching records while you type away,</em>
<em>;   without waiting for you to press &lt;Enter&gt;.</em>
<em>; - Added internal switch (TrackKeyPhrase) to track search-string.</em>
<em>; - Added internal switch (ToolTipFilename) to show filename</em>
<em>;   using tooltip.</em>
<em>;</em>
<em>; * v2.0.1</em>
<em>; - Added horizontal scrollbar to ListBox so that very</em>
<em>;   long records will not be cut-off in the middle.</em>
<em>;</em>
<em>; * v2.0.2</em>
<em>; - Allowed user to add their own customised list of directories</em>
<em>;   to be included in the scanning. User just needs to create a</em>
<em>;   text file 'Seek.dir' in the same directory as Seek.exe or</em>
<em>;   Seek.ahk, and specify the full path of the directory to be</em>
<em>;   added, one directory per line. Do not enclose the path in</em>
<em>;   quotes or double-quotes.</em>
<em>;</em>
<em>; * v2.0.3</em>
<em>; - Added /on option to DIR-command to sort by name.</em>
<em>; - Fuzzy search when user enters multiple query strings,</em>
<em>;   separated by space, for e.g. &quot;med pla&quot;. It's a match</em>
<em>;   when all the strings (&quot;med&quot; &amp; &quot;pla&quot;) are found. This</em>
<em>;   will match &quot;Media Player&quot;, &quot;Macromedia Flash Player&quot;,</em>
<em>;   &quot;Play Medieval King&quot;, &quot;medpla&quot;, &quot;plamed&quot;.</em>
<em>; - Corrected tab-movement sequence by adding all buttons</em>
<em>;   right from the start, but disable them until they can</em>
<em>;   be used.</em>
<em>; - Added status bar to replace tooltip-feedback.</em>
<em>; - Removed obsolete internal switch (ToolTipFilename).</em>
<em>; - Replaced the use of &quot;dir&quot; command with AutoHotkey's</em>
<em>;   own &quot;Loop&quot; command for scanning directory contents.</em>
<em>;   &quot;dir&quot; cannot handle extended character set and thus</em>
<em>;   non-English (e.g German) directory and filename are</em>
<em>;   captured wrongly. (Thanks Wolfgang Bujatti and</em>
<em>;   Sietse Fliege for testing this modification)</em>
<em>; - Added internal switch (ScanMode) to define whether</em>
<em>;   files and/or directories are to be included in scan.</em>
<em>; - Replaced hardcoded directory paths of Start Menu with</em>
<em>;   built-in variables A_StartMenu, A_StartMenuCommon.</em>
<em>;   With this, Seek now works for different locales with</em>
<em>;   different naming convention of the Start Menu.</em>
<em>;   (Thanks Wolfgang Bujatti and Sietse Fliege for help</em>
<em>;   in testing another method before these new variables</em>
<em>;   are available.)</em>
<em>; - Added the pre-selection of the last-run program</em>
<em>;   record so that a quick double-&lt;ENTER&gt; will run it.</em>
<em>;</em>
<em>;*****************************************************************</em>

<em>;**************************</em>
<em>;&lt;--- BEGIN OF PROGRAM ---&gt;</em>
<em>;**************************</em>

<em>;==== Your Customisation ===================================</em>

<em>; Specify which program to use when opening a directory.</em>
<em>; If the program cannot be found or is not specified</em>
<em>; (i.e. variable is unassigned or assigned a null value),</em>
<em>; the default Explorer will be used.</em>
dirExplorer = E:\utl\xplorer2_lite\xplorer2.exe

<em>; User's customised list of additional directories to be</em>
<em>; included in the scanning. The full path must not be</em>
<em>; enclosed by quotes or double-quotes. If this file is</em>
<em>; missing, only the default directories will be scanned.</em>
SeekMyDir = %A_ScriptDir%\Seek.dir

<em>; Specify the filename and directory location to save</em>
<em>; the cached directory/program listing. There is no</em>
<em>; need to change this unless you want to.</em>
dirListing = %A_Temp%\_Seek.list

<em>; Specify the filename and directory location to save</em>
<em>; the cached key word/phrase of last search. There is</em>
<em>; no need to change this unless you want to.</em>
keyPhrase = %A_Temp%\_Seek.key

<em>; Track search string (ON/OFF)</em>
<em>; If ON, the last-used query string will be re-used as</em>
<em>; the default query string the next time you run Seek.</em>
<em>; If OFF, the last-used query string will not be tracked</em>
<em>; and there will not be a default query string value the</em>
<em>; next time you run Seek.</em>
TrackKeyPhrase = ON

<em>; Specify what should be included in scan.</em>
<em>; 0: Directories are excluded (only files).</em>
<em>; 1: All files and directories are included.</em>
<em>; 2: Only directories are included (no files).</em>
ScanMode = 1

<em>;...........................................................</em>

<em>; INIT</em>
<em>;#NoTrayIcon</em>
StringCaseSense, Off
version = Seek v2.0.3

<em>; DISPLAY HELP INSTRUCTIONS</em>
If 1 in --help,-help,/h,-h,/?,-?
{
    MsgBox,, %version%, Navigating the Start Menu can be a hassle, especially if you have installed many programs over time. 'Seek' lets you specify a case-insensitive key word/phrase that it will use to filter only the matching programs and directories from the Start Menu, so that you can easily open your target program from a handful of matched entries. This eliminates the drudgery of searching and traversing the Start Menu.`n`nI have a lot of fun coding this, and hope you will enjoy using it too. Feel free to drop me an email with your comments and feedback at: phi1618 (*a.t*) gmail :D0T: com.`n`nOptions:`n  -cache`tUse the cached directory-listing if available (this is the default mode when no option is specified)`n  -scan`tForce a directory scan to retrieve the latest directory listing`n  -scex`tScan &amp; exit (this is useful for scheduling the potentially time-consuming directory-scanning as a background job)`n  -help`tShow this help
    Goto QuitNoSave
}

<em>; CHECK THAT THE MANDATORY ENVIRONMENT VARIABLES EXIST AND ARE VALID</em>
<em>; *TMP*</em>
IfNotExist, %A_Temp% <em>; PATH DOES NOT EXIST</em>
{
    MsgBox This mandatory environment variable is either not defined or invalid:`n`n    TMP = %A_Temp%`n`nPlease fix it before running Seek.
    Goto QuitNoSave
}

<em>; IF NOT SCAN-AND-EXIT</em>
IfNotEqual 1, -scex
{
    <em>; RETRIEVE THE LAST USED KEY-PHRASE FROM CACHE FILE</em>
    <em>; TO BE USED AS THE DEFAULT QUERY STRING</em>
    If TrackKeyPhrase = ON
    {
        FileReadLine, PrevKeyPhrase, %keyPhrase%, 1
        FileReadLine, PrevOpenTarget, %keyPhrase%, 2
    }
    NewKeyPhrase = %PrevKeyPhrase%
    NewOpenTarget = %PrevOpenTarget%

    <em>; ADD THE TEXT BOX FOR USER TO ENTER THE QUERY STRING</em>
    Gui, 1:Add, Edit, vFilename W600, %NewKeyPhrase%

    <em>; ADD MY FAV TAGLINE</em>
    Gui, 1:Add, Text, X625 Y10, What do you seek, my friend?

    <em>; ADD THE STATUS BAR FOR PROVIDING FEEDBACK TO USER</em>
    Gui, 1:Add, Text, vStatusBar X10 Y31 R1 W764

    <em>; ADD THE SELECTION LISTBOX FOR DISPLAYING SEARCH RESULTS</em>
    Gui, 1:Add, ListBox, vOpenTarget gTargetSelection X10 Y53 R28 W764 HScroll Disabled, %List%

    <em>; ADD THESE BUTTONS, BUT DISABLE THEM FOR NOW</em>
    Gui, 1:Add, Button, gButtonOPEN vButtonOPEN Default X10 Y446 Disabled, Open
    Gui, 1:Add, Button, gButtonOPENDIR vButtonOPENDIR X59 Y446 Disabled, Open Directory
    Gui, 1:Add, Button, gButtonSCANSTARTMENU vButtonSCANSTARTMENU X340 Y446 Disabled, Scan Start-Menu

    <em>; ADD THE EXIT BUTTON</em>
    Gui, 1:Add, Button, gButtonEXIT X743 Y446, Exit

    <em>; POP-UP THE QUERY WINDOW</em>
    Gui, 1:Show, Center, %version%
}

<em>; ENABLE RE-SCANNING OF LATEST DIRECTORY LISTING</em>
If 1 in -scan,-scex
    rescan = Y
<em>; CHECK WHETHER THE DIRECTORY LISTING CACHE FILE ALREADY EXISTS. IF NOT, DO A RE-SCAN.</em>
Else IfNotExist, %dirListing%
    rescan = Y

If rescan = Y <em>; DO A RE-SCAN</em>
{
    <em>; SHOW STATUS UNLESS USER SPECIFIES SCAN-AND-EXIT OPTION</em>
    IfNotEqual 1, -scex
        GuiControl,, StatusBar, Scanning directory listing...

    <em>; SCAN START-MENU AND STORE DIRECTORY/PROGRAM LISTINGS IN CACHE FILE</em>
    Gosub ScanStartMenu

    <em>; QUIT IF USER SPECIFIES SCAN-AND-EXIT OPTION</em>
    IfEqual 1, -scex, Goto, QuitNoSave
}

GuiControl,, StatusBar, Retrieving last query result...

<em>; RETRIEVE THE MATCHING LIST FOR THE LAST USED KEY-PHRASE</em>
Gosub SilentFindMatches

<em>; REMOVE THE STATUS TEXT</em>
GuiControl,, StatusBar,

<em>; DIRECTORY LISTING IS NOW LOADED. ENABLE THE OTHER BUTTONS.</em>
<em>; THESE BUTTONS ARE DISABLED EARLIER BECAUSE THEY SHOULD NOT</em>
<em>; BE FUNCTIONAL UNTIL THIS PART OF THE SCRIPT.</em>
GuiControl, 1:Enable, ButtonOPEN
GuiControl, 1:Enable, ButtonOPENDIR
GuiControl, 1:Enable, ButtonSCANSTARTMENU

<em>; TURN ON INCREMENTAL SEARCH</em>
SetTimer, tIncrementalSearch, 500

<em>; REFRESH THE GUI</em>
Gosub EnterQuery

Return

<em>;***********************************************************</em>
<em>;                                                          *</em>
<em>;                 END OF MAIN PROGRAM                      *</em>
<em>;                                                          *</em>
<em>;***********************************************************</em>


<em>;=== BEGIN ButtonSCANSTARTMENU EVENT =======================</em>

ButtonSCANSTARTMENU:

Gui, 1:Submit, NoHide
GuiControl,, StatusBar, Scanning directory listing...

<em>; DISABLE LISTBOX WHILE SCANNING IS IN PROGRESS</em>
GuiControl, 1:Disable, OpenTarget
GuiControl, 1:Disable, ButtonEXIT
GuiControl, 1:Disable, ButtonOPEN
GuiControl, 1:Disable, ButtonOPENDIR
GuiControl, 1:Disable, ButtonSCANSTARTMENU

<em>; DO THE SCANNING</em>
Gosub ScanStartMenu

<em>; INFORM USER THAT SCANNING HAS COMPLETED</em>
If Filename =
{
    <em>; IF QUERY STRING IS EMPTY...</em>
    GuiControl, 1:Enable, ButtonEXIT
    GuiControl, 1:Enable, ButtonOPEN
    GuiControl, 1:Enable, ButtonSCANSTARTMENU
    GuiControl,, StatusBar, Scan completed.
    Gosub EnterQuery
}
Else
{
    <em>; IF QUERY STRING EXISTS...</em>
    <em>; FILTER FOR SEARCH STRING WITH THE NEW LISTING</em>
    NewKeyPhrase =
    Gosub FindMatches
}
Return

<em>;... END ButtonSCANSTARTMENU EVENT .........................</em>


<em>;=== BEGIN ScanStartMenu SUBROUTINE ========================</em>
<em>; SCAN THE START-MENU AND STORE THE DIRECTORY/PROGRAM</em>
<em>; LISTINGS IN A CACHE FILE</em>
ScanStartMenu:

<em>; DEFINE THE DIRECTORY PATHS TO RETRIEVE.</em>
<em>; THE PATH MUST NOT BE ENCLOSED BY QUOTES OR DOUBLE-QUOTES.</em>
<em>;</em>
<em>; FOR ENGLISH VERSION OF WINDOWS</em>
scanPath = %A_StartMenu%|%A_StartMenuCommon%

<em>; INCLUDE ADDITIONAL USER-DEFINED PATHS FOR SCANNING</em>
IfExist, %SeekMyDir%
{
    Loop, read, %SeekMyDir%
    {
        IfNotExist, %A_LoopReadLine%
            MsgBox, 8192, %version%, Processing your customised directory list...`n`n&quot;%A_LoopReadLine%&quot; does not exist and will be excluded from the scanning.`nPlease update [ %SeekMyDir% ].
        Else
            scanPath = %scanPath%|%A_LoopReadLine%
    } 
}

<em>; DELETE EXISTING FILE BEFORE CREATING A NEW VERSION</em>
FileDelete, %dirListing%

<em>; SCAN DIRECTORY LISTING (DELIMITER = |) BY RECURSING</em>
<em>; EACH DIRECTORY TO RETRIEVE THE CONTENTS. HIDDEN FILES</em>
<em>; ARE EXCLUDED.</em>
Loop, parse, scanPath, |
{
    Loop, %A_LoopField%\*, %ScanMode%, 1
    {
        FileGetAttrib, fileAttrib, %A_LoopFileFullPath%
        IfNotInString, fileAttrib, H <em>; EXCLUDE HIDDEN FILE</em>
            FileAppend, %A_LoopFileFullPath%`n, %dirListing%
    }
}

Return

<em>;... END ScanStartMenu SUBROUTINE ..........................</em>


<em>;=== BEGIN FindMatches SUBROUTINE ==========================</em>
<em>; SEARCH AND DISPLAY ALL MATCHING RECORDS IN THE LISTBOX</em>
FindMatches:

Gui, 1:Submit, NoHide
CurFilename = %Filename%
GuiControl,, StatusBar, 

<em>; CHECK FOR EMPTY QUERY STRING</em>
If CurFilename =
{
    MsgBox, 8192, %version%, Please enter the key word/phrase to search for.
    Goto EnterQuery
}

<em>; tIncrementalSearch IS BEING INTERRUPTED. LET IT FINISHES.</em>
If NewKeyPhrase &lt;&gt; %CurFilename%
{
    <em>; INFORM USER THAT PATIENCE IS A VIRTUE</em>
    GuiControl,, StatusBar, Seeking...
    ResumeFindMatches = TRUE
    Return
}

If List = |
{
    <em>; NOT EVEN A SINGLE MATCHING RECORD IS FOUND.</em>
    <em>; LET USER MODIFY THE QUERY STRING AND TRY AGAIN.</em>
    MsgBox, 8192, %version%, The query string &quot;%CurFilename%&quot; does not match any record. Try again.
    GuiControl, 1:Disable, ButtonOPENDIR
    GuiControl, 1:Enable, ButtonSCANSTARTMENU
    Goto EnterQuery
}
Else
{
    <em>; SELECT THE FIRST RECORD IF NO OTHER RECORD HAS BEEN SELECTED</em>
    Gui, 1:Submit, NoHide
    GuiControl, 1:Enable, OpenTarget
    GuiControl, 1:Enable, ButtonOPEN
    GuiControl, 1:Enable, ButtonOPENDIR
    GuiControl, 1:Enable, ButtonSCANSTARTMENU
    GuiControl, Focus, OpenTarget
    If OpenTarget =
        GuiControl, 1:Choose, OpenTarget, |1
}

<em>; REFRESH GUI</em>
Gui, 1:Show, Center, %version%

Return

<em>;... END FindMatches SUBROUTINE ............................</em>


<em>;=== BEGIN SilentFindMatches SUBROUTINE ====================</em>

SilentFindMatches:

Gui, 1:Submit, NoHide
sfmFilename = %Filename%

<em>; FILTER MATCHING RECORDS BASED ON USER QUERY STRING</em>
List = |
If sfmFilename &lt;&gt;
{
    Loop, read, %dirListing%
    {
        Gui, 1:Submit, NoHide
        tFilename = %Filename%
        If sfmFilename &lt;&gt; %tFilename%
        {
            <em>; USER HAS CHANGED THE SEARCH STRING. THERE IS NO POINT</em>
            <em>; TO CONTINUE SEARCHING USING THE OLD STRING, SO ABORT.</em>
            Return
        }
        Else
        {
            <em>; APPEND MATCHING RECORDS INTO THE LIST</em>
            SplitPath, A_LoopReadLine, name, dir, ext, name_no_ext, drive
            MatchFound = Y
            Loop, parse, sfmFilename, %A_Space%
            {
                IfNotInString, name, %A_LoopField%
                {
                    MatchFound = N
                    Break
                }
            }
            IfEqual, MatchFound, Y
            {
                <em>; ADD RECORD TO LIST</em>
                List = %List%%A_LoopReadLine%|

                <em>; PRE-SELECT IF THIS MATCHES THE LAST-RUN PROGRAM</em>
                If (A_LoopReadLine = PrevOpenTarget &amp;&amp; sfmFilename = PrevKeyPhrase)
                    List = %List%|
            }
        }
    }
}

<em>; REFRESH LIST WITH SEARCH RESULTS</em>
GuiControl, 1:, OpenTarget, %List%

If List = |
{
    <em>; NO MATCHING RECORD IS FOUND</em>
    <em>; DISABLE LISTBOX</em>
    GuiControl, 1:Disable, OpenTarget
    GuiControl, 1:Disable, ButtonOPENDIR
}
Else
{
    <em>; MATCHING RECORDS ARE FOUND</em>
    <em>; ENABLE LISTBOX</em>
    GuiControl, 1:Enable, OpenTarget
    GuiControl, 1:Enable, ButtonOPENDIR
}

<em>; REFRESH GUI</em>
Gui, 1:Show, Center, %version%

Return

<em>;... END SilentFindMatches SUBROUTINE ......................</em>


<em>;=== BEGIN EnterQuery SUBROUTINE ===========================</em>
<em>; REFRESH GUI AND LET USER ENTERS SEARCH STRING</em>
EnterQuery:
GuiControl, Focus, Filename
GuiControl, 1:Enable, ButtonOPEN
Gui, 1:Show, Center, %version%
Return
<em>;... END EnterQuery SUBROUTINE .............................</em>


<em>;=== BEGIN TargetSelection EVENT ===========================</em>

TargetSelection:
Gui, 1:Submit, NoHide

<em>; DOUBLE-CLICK DETECTION TO LAUNCH PROGRAM</em>
If A_GuiControlEvent = DoubleClick
{
    Gosub ButtonOPEN
}
Else
{
    <em>; STUB - FOR FUTURE USE</em>
    If A_GuiControlEvent = Normal
    {
        <em>; DO NOTHING FOR NOW</em>
    }
}

Return

<em>;... END TargetSelection EVENT .............................</em>


<em>;=== BEGIN ButtonOPEN EVENT ================================</em>

<em>; USER CLICKED ON 'OPEN' BUTTON OR PRESSED &lt;ENTER&gt;</em>
ButtonOPEN:
Gui, 1:Submit, NoHide

<em>; FIND OUT WHERE THE KEYBOARD FOCUS WAS. IF IT'S THE</em>
<em>; TEXT FIELD, RUN THE QUERY TO FIND MATCHES. ELSE, IT</em>
<em>; MUST BE FROM THE LISTBOX.</em>
GuiControlGet, focusControl, 1:Focus
If focusControl = Edit1
{
    GuiControl, Focus, OpenTarget
    GuiControl, 1:Disable, OpenTarget
    GuiControl, 1:Disable, ButtonOPENDIR
    GuiControl, 1:Disable, ButtonSCANSTARTMENU
    Goto FindMatches
}

<em>; NO RECORD FROM THE LISTBOX IS SELECTED</em>
If OpenTarget =
{
    MsgBox, 8192, %version%, Please make a selection before hitting &lt;Enter&gt;.`nPress &lt;Esc&gt; to exit.
    Goto EnterQuery
}

<em>; SELECTED RECORD DOES NOT EXIST (FILE OR DIRECTORY NOT FOUND)</em>
IfNotExist, %OpenTarget%
{
    MsgBox, 8192, %version%, %OpenTarget% does not exist. This means that the directory cache is outdated. You may click on the 'Scan Start-Menu' button below to update the directory cache with your latest directory listing now.
    Goto EnterQuery
}

<em>; CHECK WHETHER THE SELECTED RECORD IS A FILE OR DIRECTORY</em>
FileGetAttrib, fileAttrib, %OpenTarget%
IfInString, fileAttrib, D <em>; IS DIRECTORY</em>
{
    Gosub sOpenDir
}
Else If fileAttrib &lt;&gt; <em>; IS FILE</em>
{
    Run, %OpenTarget%
}
Else
{
    MsgBox %OpenTarget% is neither a DIRECTORY or a FILE. This shouldn't happen. Seek cannot proceed. Quitting...
}

Goto Quit

<em>;... END ButtonOPEN EVENT ..................................</em>


<em>;=== BEGIN ButtonOPENDIR EVENT =============================</em>

<em>; USER CLICKED ON 'OPEN DIRECTORY' BUTTON</em>
ButtonOPENDIR:
Gui, 1:Submit, NoHide

<em>; CHECK THAT USER HAS SELECTED A RECORD ALREADY</em>
If OpenTarget =
{
    MsgBox, 8192, %version%, Please make a selection first.
    Goto EnterQuery
}

<em>; RUN SUBROUTINE TO OPEN A DIRECTORY</em>
Gosub sOpenDir

Goto Quit

<em>;... END ButtonOPENDIR EVENT ...............................</em>


<em>;=== BEGIN sOpenDir SUBROUTINE =============================</em>

sOpenDir:

<em>; IF USER SELECTED A FILE-RECORD INSTEAD OF A DIRECTORY-RECORD,</em>
<em>; EXTRACT THE DIRECTORY PATH. (I'M USING DriveGet INSTEAD OF</em>
<em>; FileGetAttrib TO ALLOW THE SCENARIO WHEREBY OpenTarget IS</em>
<em>; INVALID BUT THE DIRECTORY PATH OF OpenTarget IS VALID.</em>
DriveGet, status, status, %OpenTarget%
If status &lt;&gt; Ready <em>; NOT A DIRECTORY</em>
{
    SplitPath, OpenTarget, name, dir, ext, name_no_ext, drive
    OpenTarget = %dir%
}

<em>; CHECK WHETHER DIRECTORY EXISTS</em>
IfNotExist, %OpenTarget%
{
    MsgBox, 8192, %version%, %OpenTarget% does not exist. This means that the directory cache is outdated. You may click on the 'Scan Start-Menu' button below to update the directory cache with your latest directory listing now.
    Goto EnterQuery
}

<em>; OPEN THE DIRECTORY</em>
IfExist, %dirExplorer%
{
    Run, &quot;%dirExplorer%&quot; &quot;%OpenTarget%&quot;, , Max <em>; OPEN WITH CUSTOMISED FILE EXPLORER</em>
}
Else
{
    Run, %OpenTarget%, , Max <em>; OPEN WITH DEFAULT WINDOWS FILE EXPLORER</em>
}
Return

<em>;... END sOpenDir SUBROUTINE ...............................</em>


<em>;=== BEGIN tIncrementalSearch EVENT ========================</em>
<em>; AUTOMATICALLY CONDUCT REAL-TIME INCREMENTAL SEARCH</em>
<em>; TO FIND MATCHING RECORDS WITHOUT WAITING FOR USER</em>
<em>; TO PRESS &lt;ENTER&gt;</em>
tIncrementalSearch:

Loop
<em>; REPEAT SEARCHING UNTIL USER HAS STOPPED CHANGING THE QUERY STRING</em>
{
    Gui, 1:Submit, NoHide
    CurFilename = %Filename%
    If NewKeyPhrase &lt;&gt; %CurFilename%
    {
        OpenTarget =
        Gosub SilentFindMatches
        NewKeyPhrase = %CurFilename%
        Sleep, 100 <em>; DON'T HOG THE CPU!</em>
    }
    Else
    {
        <em>; QUERY STRING HAS STOPPED CHANGING</em>
        Break
    }
}

<em>; USER HAS HIT &lt;ENTER&gt; TO LOOK FOR MATCHING RECORDS.</em>
<em>; RUN FindMatches NOW.</em>
If ResumeFindMatches = TRUE
{
    ResumeFindMatches = FALSE
    Gosub FindMatches
}

<em>; CONTINUE MONITORING FOR CHANGES</em>
SetTimer, tIncrementalSearch, 500

Return

<em>;... END tIncrementalSearch EVENT ..........................</em>


<em>;=== BEGIN Quit SUBROUTINE =================================</em>

Quit:
ButtonEXIT:
GuiClose:
GuiEscape:

Gui, 1:Submit, NoHide

<em>; SAVE THE KEY WORD/PHRASE FOR NEXT RUN IF IT HAS CHANGED</em>
If TrackKeyPhrase = ON
{
    If (PrevKeyPhrase &lt;&gt; Filename || PrevOpenTarget &lt;&gt; OpenTarget)
    {
        FileDelete, %keyPhrase%
        FileAppend, %Filename%`n, %keyPhrase%
        FileAppend, %OpenTarget%`n, %keyPhrase%
    }
}

QuitNoSave:
ExitApp <em>; JOB DONE. G'DAY!</em>

<em>;... END Quit SUBROUTINE ...................................</em>


<em>;************************</em>
<em>;&lt;--- END OF PROGRAM ---&gt;</em>
<em>;************************</em>

<em>; /* vim: set noexpandtab shiftwidth=4: */</em>
</pre>
</body>
</html>
